#ifndef __R_GEOMETRY_S4_H__
#define __R_GEOMETRY_S4_H__

#include "R_S.h"
#include "WrapDefs.h"
#include "Geometry_Wrap.h"
#include "R_Tools.h"
#include "Geometry/UGGeoPoint.h"
#include "Geometry/UGGeoLine.h"
#include "Geometry/UGGeoRegion.h"

namespace RSuperMap{

#if defined(RCPP_VERSION) && RCPP_VERSION <= Rcpp_Version(0,10,6)
#define SetSexp setSEXP
#define AsSexp  asSexp
#else
#define SetSexp set__
#define AsSexp  get__
#endif

	using namespace Rcpp;
	using namespace UGC;
	using Rcpp::S4;
	using namespace RSuperMap;

	template <typename UGGeometry>
	void Geometry_delete_finalizer(UGGeometry* obj){
		Geometry_wrap_delete(obj);
	}

	template <typename UGGeoPoint>
	void GeoPoint_delete_finalizer(UGGeoPoint* obj){
		GeoPoint_wrap_detete(obj);
	}

	template <typename UGGeoLine>
	void GeoLine_delete_finalizer(UGGeoLine* obj){
		GeoLine_wrap_delete(obj);
	}

	template <typename UGGeoRegion>
	void GeoRegion_delete_finalizer(UGGeoRegion* obj){
		GeoRegion_wrap_delete(obj);
	}


	class S4_Geometry : public Rcpp::S4 {
	public: 
		S4_Geometry(const UGGeometry* pGeometry) : S4("Geometry") {
			slot("pointer") = Rcpp::XPtr<UGGeometry, Rcpp::PreserveStorage, Geometry_delete_finalizer>(const_cast<UGGeometry*>(pGeometry));
		}

		S4_Geometry(const S4_Geometry& other) : S4() { SetSexp(other.AsSexp()); }

		S4_Geometry& operator=(const S4_Geometry& other) {
			SetSexp(other.AsSexp());
			return *this;
		}
	};

	class S4_GeoPoint : public Rcpp::S4 {
	public:
		S4_GeoPoint(const UGGeoPoint* pGeometry) : S4("GeoPoint") {
			slot("pointer") = Rcpp::XPtr<UGGeoPoint,  Rcpp::PreserveStorage, GeoPoint_delete_finalizer>(const_cast<UGGeoPoint*>(pGeometry));
		}

		S4_GeoPoint(const S4_GeoPoint& other) : S4() { SetSexp(other.AsSexp()); }

		S4_GeoPoint& operator=(const S4_GeoPoint& other) {
			SetSexp(other.AsSexp());
			return *this;
		}
	};

	class S4_GeoLine : public Rcpp::S4 {
	public:
		S4_GeoLine(const UGGeoLine* pGeometry) : S4("GeoLine") {
			slot("pointer") = Rcpp::XPtr<UGGeoLine,  Rcpp::PreserveStorage, GeoLine_delete_finalizer>(const_cast<UGGeoLine*>(pGeometry));
		}

		S4_GeoLine(const S4_GeoLine& other) : S4() { SetSexp(other.AsSexp()); }

		S4_GeoLine& operator=(const S4_GeoLine& other) {
			SetSexp(other.AsSexp());
			return *this;
		}
	};


	class S4_GeoRegion : public Rcpp::S4 {
	public:
		S4_GeoRegion(const UGGeoRegion* pGeometry) : S4("GeoRegion") {
			slot("pointer") = Rcpp::XPtr<UGGeoRegion,  Rcpp::PreserveStorage, GeoRegion_delete_finalizer>(const_cast<UGGeoRegion*>(pGeometry));
		}

		S4_GeoRegion(const S4_GeoRegion& other) : S4() { SetSexp(other.AsSexp()); }

		S4_GeoRegion& operator=(const S4_GeoRegion& other) {
			SetSexp(other.AsSexp());
			return *this;
		}
	};

#undef SetSexp
#undef AsSexp
}

#endif
